package com.eqxiu.ieditor.weixin.config;

import java.sql.SQLException;
import java.util.Collections;

import javax.sql.DataSource;

import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
public class DatabaseConfig {

    @Autowired
    private Environment env;

    @Bean
    public DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setUrl(env.getProperty("spring.datasource.url"));
        ds.setUsername(env.getProperty("spring.datasource.username"));
        ds.setPassword(env.getProperty("spring.datasource.password"));
        ds.setDriverClassName(env.getProperty("spring.datasource.driverClassName"));
        ds.setMaxActive(env.getProperty("spring.datasource.max-active", Integer.class, 30));
        ds.setInitialSize(env.getProperty("spring.datasource.min-idle", Integer.class, 2));
        ds.setMinIdle(env.getProperty("spring.datasource.min-idle", Integer.class, 2));
        ds.setLoginTimeout(env.getProperty("spring.datasource.maxWait", Integer.class, 20000));
        ds.setQueryTimeout(env.getProperty("spring.datasource.maxWait", Integer.class, 20000));
        ds.setTestWhileIdle(true);
        ds.setTimeBetweenEvictionRunsMillis(
            env.getProperty("spring.datasource.timeBetweenEvictionRunsMillis", Long.class));
        ds.setMinEvictableIdleTimeMillis(env.getProperty("spring.datasource.minEvictableIdleTimeMillis", Long.class));
        ds.setMinEvictableIdleTimeMillis(30000);
        ds.setValidationQuery("SELECT 'x' from dual");
        ds.setTestOnBorrow(false);
        ds.setTestOnReturn(false);
        ds.setPoolPreparedStatements(true);
        ds.setMaxPoolPreparedStatementPerConnectionSize(20);
        try {
            ds.setFilters(env.getProperty("spring.datasource.filters"));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        ds.setConnectionProperties(env.getProperty("spring.datasource.connectionProperties"));
        return ds;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

    @Bean
    public TransactionInterceptor txAdvice() {
        MatchAlwaysTransactionAttributeSource source = new MatchAlwaysTransactionAttributeSource();
        RuleBasedTransactionAttribute transactionAttribute = new RuleBasedTransactionAttribute();
        transactionAttribute.setName("*");
        transactionAttribute.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        source.setTransactionAttribute(transactionAttribute);
        TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager(), source);
        return txAdvice;
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* com.eqxiu.ieditor.*.service.impl.*(..))");
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }

}
